﻿Imports Aricie.DNN.Modules.LuceneSearch.ModuleProviders
Imports Aricie.DNN.Modules.LuceneSearch.Business
Imports Aricie.Services
Imports DotNetNuke.Services.Search
Imports DotNetNuke.Entities.Modules

Namespace Aricie.DNN.Modules.LuceneSearch.ModuleProviders


    ''' <summary>
    ''' L'objectif de ce provider est de pouvoir fusionner les Html/Text présents sur une page en un seul élément de recherche.
    ''' Cela doit pouvoir permettre d'éviter sur les sites Novartis d'avoir la même page qui apparaisse lorsque la recherche renvoie des Text/HTML appartenant
    ''' à la même page.
    ''' On va utiliser un dictionnaire qui va réunir les paramétrages par thread (de manière à éviter les collisions en cas d'indexation parallèle entre deux processus)
    ''' Pour cela, on signale au provider qu'on commence l'upgrade, et il initialise le dictionnaire de correspondance tab -> searchItem pour le thread courant.
    ''' Puis il va ensuite vérifier le tabId de chaque élément qui lui est passé
    ''' Si le tabid existe déjà dans le dictionnaire, alors c'est qu'on a déjà un Text/HTML qui a été mis à jour pour cette page; on fusionne le contenu du nouveau Text/HTML avec l'ancien
    ''' Si le tabid n'existe pas, on le rajoute en changeant son titre à celui de la page.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class MergeHtmlProvider
        Implements ILuceneSearchableUpgrade
        Implements ISearchable
        Implements IUpgradeEventsHandlerProvider

        Private _ThreadToInsert As New Dictionary(Of Integer, Integer)
        Private _ThreadToMerge As New Dictionary(Of Integer, Integer)
        Private _ThreadToMerger As New Dictionary(Of Integer, Dictionary(Of String, LuceneSearchItemInfo))
        Private _Lock As New Object

        Private ReadOnly Property ThreadId As Integer
            Get
                Return System.Threading.Thread.CurrentThread.ManagedThreadId
            End Get
        End Property

        Private ReadOnly Property Key(PortalId As Integer, TabId As Integer)
            Get
                Return String.Format("{0}-{1}", PortalId, TabId)
            End Get
        End Property

        Private ReadOnly Property CurrentSearchItem(PortalId As Integer, TabId As Integer) As LuceneSearchItemInfo
            Get
                Dim LSI As LuceneSearchItemInfo = Nothing
                _ThreadToMerger(ThreadId).TryGetValue(Key(PortalId, TabId), LSI)
                Return LSI
            End Get
        End Property

        Public Sub UpgradeSearchItem(portalId As Integer, ByRef searchItem As LuceneSearchItemInfo) Implements ILuceneSearchableUpgrade.UpgradeSearchItem
            ' on vérifie si le tabid est déjà rentré
            Dim CSI = CurrentSearchItem(portalId, searchItem.TabId)
            If (CSI Is Nothing) Then
                _ThreadToInsert(ThreadId) += 1
                ' rajoutons le  titre et la description de la page
                searchItem.Title = searchItem.TabInfo.TabName
                searchItem.Description = searchItem.TabInfo.Description
                searchItem.IndexingStatus = IndexingItemStatus.Ok ' on force le indexing status

                _ThreadToMerger(ThreadId)(Key(searchItem.PortalId, searchItem.TabId)) = searchItem
            Else
                _ThreadToMerge(ThreadId) += 1
                ' on a déjà un élément, fusionnons le nouveau avec celui qui est déjà passé
                Merge(CSI, searchItem)
            End If
        End Sub

        Private Sub Merge(CSI As LuceneSearchItemInfo, NSI As LuceneSearchItemInfo)
            NSI.IndexingStatus = IndexingItemStatus.Skipped
            CSI.Content += " " & NSI.Content
        End Sub

        Public Sub BeginUpgrade(UEHPA As UpgradeEventsHandlerProviderArguments) Implements IUpgradeEventsHandlerProvider.BeginUpgrade
            SyncLock _Lock ' ce lock n'est peut être pas nécessaire, il faudrait analyser ce qui se passe lors de l'utilisation d'un thread pool sous DNN
                If (Not _ThreadToMerger.ContainsKey(ThreadId)) Then
                    _ThreadToMerger.Add(ThreadId, New Dictionary(Of String, LuceneSearchItemInfo))
                    _ThreadToInsert.Add(ThreadId, 0)
                    _ThreadToMerge.Add(ThreadId, 0)
                    Dim Logger = New Global.Aricie.DNN.Modules.LuceneSearch.Logging.StepLogger(UEHPA.Settings.LogIndexingProcess, UEHPA.PortalId)
                    Logger.LogStep(LuceneLogType.Upgrade, "Merge upgrade started")
                End If
            End SyncLock
        End Sub

        Public Sub EndUpgrade(UEHPA As UpgradeEventsHandlerProviderArguments) Implements IUpgradeEventsHandlerProvider.EndUpgrade
            Try
                SyncLock _Lock ' ce lock n'est peut être pas nécessaire, il faudrait analyser ce qui se passe lors de l'utilisation d'un thread pool sous DNN
                    Dim Logger = New Global.Aricie.DNN.Modules.LuceneSearch.Logging.StepLogger(UEHPA.Settings.LogIndexingProcess, UEHPA.PortalId)
                    Logger.LogStep(LuceneLogType.Upgrade, String.Format("Merge upgrade ended: documents inserted {0} / documents merged {1}", _ThreadToInsert(ThreadId), _ThreadToMerge(ThreadId)))
                    _ThreadToMerge.Remove(ThreadId)
                    _ThreadToInsert.Remove(ThreadId)
                    _ThreadToMerger.Remove(ThreadId)
                End SyncLock
            Catch ex As Exception
                Aricie.Services.ExceptionHelper.LogException(ex)
            End Try
        End Sub

        Public Function GetSearchItems(ModInfo As DotNetNuke.Entities.Modules.ModuleInfo) As DotNetNuke.Services.Search.SearchItemInfoCollection Implements ISearchable.GetSearchItems
            'Dim t As Type = ReflectionHelper.CreateType("DotNetNuke.Modules.HtmlPro.HtmlTextController, DotNetNuke.Professional.HtmlPro")
            Dim t As Type = ReflectionHelper.CreateType("DotNetNuke.Modules.Html.HtmlTextController, DotNetNuke.Modules.Html")
            Dim provider = ReflectionHelper.CreateObject(t)
            Dim Results As SearchItemInfoCollection = DirectCast(t.InvokeMember("GetSearchItems", Reflection.BindingFlags.InvokeMethod, Nothing, provider, New Object() {ModInfo}), SearchItemInfoCollection)

            Dim ChangedResults As New SearchItemInfoCollection

            For Each sii As SearchItemInfo In Results
                ' on supprime le moduleId du searchItem pour indiquer qu'on veut travailler uniquement avec les droits de la page
                ' auparavant on le stocke dans la searchKey
                Dim lsii As LuceneSearchItemInfo = LuceneSearchItemInfo.GetLuceneSearchItem(sii, ModInfo.PortalID, "NovartisHtmlProvider")
                lsii.Description = System.Web.HttpUtility.HtmlDecode(lsii.Description) 'Pourquoi ces decode sont ils nécessaires?
                lsii.Content = System.Web.HttpUtility.HtmlDecode(lsii.Content) ' idem
                lsii.TabId = ModInfo.TabID
                lsii.SearchKey = "HTMLMerged_" & Key(ModInfo.PortalID, ModInfo.TabID)
                lsii.GUID = String.Empty
                lsii.ModuleId = -1 ' nous ne sommes liés à aucun module
                ChangedResults.Add(lsii)
            Next

            Return ChangedResults
        End Function
    End Class
End Namespace